home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 16
/
CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso
/
CUCD
/
Utilities
/
Datatypes
/
acbm
/
dispatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-30
|
35KB
|
1,103 lines
/*
**
** $VER: dispatch.c 1.1 (30.5.97)
** acbm.datatype 1.1
**
** Dispatch routine for a DataTypes class
**
** Written 1996/97 by Roland 'Gizzy' Mainz
** Original example source from David N. Junod
**
*/
/* main includes */
#include "classbase.h"
/* ansi includes */
#include <limits.h>
/*****************************************************************************/
/* local prototypes */
static LONG LoadACBM( struct ClassBase *, Object * );
static BOOL CMAP2Object( struct ClassBase *, Object *, UBYTE *, ULONG );
static LONG LoadABITBody( struct BitMap *, struct BitMapHeader *, BYTE *, ULONG );
static ULONG SaveIFFACBM( struct ClassBase *, Object *, struct dtWrite * );
static struct IFFHandle *CreateDOSIFFHandle( struct ClassBase *, BPTR );
static LONG PutIFFObjectInfo( struct ClassBase *, struct IFFHandle *, STRPTR, STRPTR, STRPTR, STRPTR, STRPTR );
static LONG PutIFFString( struct ClassBase *, struct IFFHandle *, ULONG, STRPTR );
static LONG PutILBMCMAP( struct ClassBase *, struct IFFHandle *, ULONG *, ULONG );
static LONG PutACBMABIT( struct ClassBase *, struct IFFHandle *, struct BitMap *, struct BitMapHeader * );
/*****************************************************************************/
/* Create "acbm.datatype" BOOPSI class */
struct IClass *initClass( struct ClassBase *cb )
{
struct IClass *cl;
/* Create our class... */
if( cl = MakeClass( ACBMDTCLASS, PICTUREDTCLASS, NULL, 0UL, 0UL ) )
{
cl -> cl_Dispatcher . h_Entry = (HOOKFUNC)Dispatch;
cl -> cl_UserData = (ULONG)cb;
AddClass( cl );
}
return( cl );
}
/*****************************************************************************/
/* IFF errors to DOS errors */
const
LONG ifferr2doserr[] =
{
0L, /* End of file (not an error). */
0L, /* End of context (not an error). */
DTERROR_INVALID_DATA, /* No lexical scope. */
ERROR_NO_FREE_STORE, /* Insufficient memory. */
ERROR_SEEK_ERROR, /* Stream read error. */
ERROR_SEEK_ERROR, /* Stream write error. */
ERROR_SEEK_ERROR, /* Stream seek error. */
DTERROR_INVALID_DATA, /* File is corrupt. */
DTERROR_INVALID_DATA, /* IFF syntax error. */
ERROR_OBJECT_WRONG_TYPE, /* Not an IFF file. */
ERROR_REQUIRED_ARG_MISSING, /* Required call-back hook missing. */
0xDEADDEAD /* Return to client. You should never see this ! */
};
/*****************************************************************************/
struct MyStackSwapStruct
{
struct StackSwapStruct stk;
struct IClass *cl;
Object *o;
Msg msg;
};
/*****************************************************************************/
/* Class entry
* Swaps stack on demand (e.g. too small stack
*/
DISPATCHERFLAGS
ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
{
struct ClassBase *cb = (struct ClassBase *)(cl -> cl_UserData);
ULONG retval;
struct MyStackSwapStruct mystk;
UBYTE *lower,
*upper,
*sp;
struct Task *ThisTask;
ULONG stacksize;
mystk . cl = cl;
mystk . o = o;
mystk . msg = msg;
ThisTask = FindTask( NULL );
stacksize = (ULONG)(((UBYTE *)(ThisTask -> tc_SPReg)) - ((UBYTE *)(ThisTask -> tc_SPLower)));
#define DTSTACKSIZE (16384UL)
/* Enougth stack ? */
if( stacksize > (DTSTACKSIZE / 2UL) )
{
retval = MyDispatch( (&mystk) );
}
else
{
/* Alloc a new stack frame... */
while( !(lower = (UBYTE *)AllocMem( DTSTACKSIZE, (MEMF_PUBLIC | MEMF_CLEAR) )) );
sp = upper = lower + DTSTACKSIZE;
mystk . stk . stk_Lower = lower;
mystk . stk . stk_Upper = (ULONG)upper;
mystk . stk . stk_Pointer = sp;
retval = SwapMe( (&mystk) );
FreeMem( lower, DTSTACKSIZE );
}
return( retval );
}
/* Swap stack and call main dispatcher */
DISPATCHERFLAGS
ULONG SwapMe( REGA0 struct MyStackSwapStruct *mystk )
{
register ULONG retval;
#define cb ((struct ClassBase *)(mystk -> cl -> cl_UserData))
StackSwap( (&(mystk -> stk)) );
retval = MyDispatch( mystk );
StackSwap( (&(mystk -> stk)) );
#undef cb
return( retval );
}
/* main class dispatcher */
DISPATCHERFLAGS
ULONG MyDispatch( REGA0 struct MyStackSwapStruct *mystk )
{
struct IClass *cl = mystk -> cl;
Object *o = mystk -> o;
Msg msg = mystk -> msg;
struct ClassBase *cb = (struct ClassBase *)(cl -> cl_UserData);
ULONG retval = 0UL;
switch( msg -> MethodID )
{
/****** acbm.datatype/OM_NEW *************************************************
*
* NAME
* OM_NEW -- Create a acbm.datatype object.
*
* FUNCTION
* The OM_NEW method is used to create an instance of the acbm.datatype
* class. This method is passed to the superclass first. After this,
* acbm.datatype parses the description file and loads bitmap,
* colormaps and so on.
*
* ATTRIBUTES
* The following attributes can be specified at creation time.
*
* DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
* attribute. DTST_FILE, DTST_CLIPBOARD and DTST_RAM are supported.
* If any other type was set in a given DTA_SourceType,
* OM_NEW will be rejected.
* Defaults to DTST_FILE.
*
* DTA_Handle -- For both supported DTST_FILE and DTST_CLIPBOARD, a
* (struct IFFHandle *) is expected.
* (DTST_FILE expects a IFF Stream handle because this is a IFF
* type DataType (DTF_IFF)).
* A DTST_RAM (create empty object) source type requires a NULL
* handle.
*
* BUGS
*
* RESULT
* If the object was created a pointer to the object is returned,
* otherwise NULL is returned.
*
******************************************************************************
*
*/
case OM_NEW:
{
struct TagItem *ti;
/* We only support DTST_FILE, DTST_CLIPBOARD or DTST_RAM as source type */
if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
{
if( ((ti -> ti_Data) != DTST_FILE) &&
((ti -> ti_Data) != DTST_CLIPBOARD) &&
((ti -> ti_Data) != DTST_RAM) )
{
SetIoErr( ERROR_OBJECT_WRONG_TYPE );
break;
}
}
/* This must not be a subclass of acbm.datatype
* (not implemented yet)
*/
if( o == (Object *)cl )
{
if( retval = DoSuperMethodA( cl, o, msg ) )
{
LONG error;
/* Load picture... */
if( error = LoadACBM( cb, (Object *)retval ) )
{
/* Something went fatally wrong, dispose object */
CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
retval = 0UL;
}
SetIoErr( error );
}
}
else
{
/* Subclasses of acbm.datatype are not implemented */
SetIoErr( ERROR_NOT_IMPLEMENTED );
}
}
break;
case OM_UPDATE:
{
if( DoMethod( o, ICM_CHECKLOOP ) )
{
break;
}
}
case OM_SET:
{
/* Pass the attributes to the picture class and force a refresh if we need it */
if( retval = DoSuperMethodA( cl, o, msg ) )
{
/* The following check statement isn't needed because OM_NEW does not allow subclasses of acbm.datatype,
* therefore, we're always the top instance...
*/
#ifdef COMMENTED_OUT
/* Top instance ? */
if( OCLASS( o ) == cl )
#endif /* COMMENTED_OUT */
{
struct RastPort *rp;
/* Get a pointer to the rastport */
if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
{
struct gpRender gpr;
/* Force a redraw */
gpr . MethodID = GM_RENDER;
gpr . gpr_GInfo = ((struct opSet *)msg) -> ops_GInfo;
gpr . gpr_RPort = rp;
gpr . gpr_Redraw = GREDRAW_UPDATE;
DoMethodA( o, (Msg)(&gpr) );
/* Release the temporary rastport */
ReleaseGIRPort( rp );
retval = 0UL;
}
}
}
}
break;
/****** acbm.datatype/DTM_WRITE **********************************************
*
* NAME
* DTM_WRITE -- Save data
*
* FUNCTION
* This method saves the object's contents to disk.
*
* If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
* superclass, picture.datatype, which writes an IFF ILBM picture.
*
* If dtw_mode is DTWM_RAW, the object saved an IFF ACBM picture to
* the filehandle given.
*
* TAGS
* None defined.
*
* RESULT
* Returns 0 for failure (IoErr() returns result2), non-zero
* for success.
*
******************************************************************************
*
*/
case DTM_WRITE:
{
struct dtWrite *dtw;
dtw = (struct dtWrite *)msg;
/* Local data format requested ? */
if( (dtw -> dtw_Mode) == DTWM_RAW )
{
retval = SaveIFFACBM( cb, o, dtw );
}
else
{
/* Pass msg to superclass (which writes an IFF ILBM picture)... */
retval = DoSuperMethodA( cl, o, msg );
}
}
break;
/* Let the superclass handle everything else */
default:
{
retval = DoSuperMethodA( cl, o, msg );
}
break;
}
return( retval );
}
static
LONG LoadACBM( struct ClassBase *cb, Object *o )
{
LONG error = 0L;
APTR fh; /* IFF stream handle */
ULONG sourcetype; /* type of stream (either DTST_FILE, DTST_CLIPBOARD or DTST_RAM */
struct BitMapHeader *bmh; /* obj's bitmapheader */
ULONG modeid = 0UL; /* picture's view mode */
/* Get file handle, handle type and BitMapHeader */
if( GetDTAttrs( o, DTA_SourceType, (&sourcetype),
DTA_Handle, (&fh),
PDTA_BitMapHeader, (&bmh),
TAG_DONE ) == 3UL )
{
struct IFFHandle *iff = NULL;
switch( sourcetype )
{
case DTST_CLIPBOARD:
case DTST_FILE:
{
/* This is an IFF DataType, datatypesclass provides an IFFHandle for us.
* (See datatypesclass autdocs for details !)
*/
iff = (struct IFFHandle *)fh;
}
break;
case DTST_RAM:
{
/* Do nothing... */
}
break;
default:
{
/* unsupported source type */
error = ERROR_NOT_IMPLEMENTED;
}
break;
}
/* Any error ? */
if( error == 0L )
{
/* Any handle to proccess ? */
if( iff )
{
struct BitMap *bm = NULL; /* resulting bitmap (e.g. PDTA_BitMap) */
struct StoredProperty *bmhdprop = NULL, /* ACBM BMHD (struct BitMapHeader) */
*camgprop = NULL, /* ACBM CAMG (amiga view mode id) */
*cmapprop = NULL, /* ACBM CMAP (colormap) */
*abitprop = NULL, /* ACBM ABIT (Amiga BITplanes */
*annoprop = NULL, /* Generic IFF ANNO (annotation) chunk */
*authprop = NULL, /* Generic IFF AUTH (author) chunk */
*copyrightprop = NULL, /* Generic IFF (C) (copyright) chunk */
*fverprop = NULL, /* Generic IFF FVER (version) chunk */
*nameprop = NULL; /* Generic IFF NAME (name) chunk */
#define NUM_PROPCHUNKS (9L)
const
LONG propchunks[ (NUM_PROPCHUNKS * 2) ] =
{
ID_ACBM, ID_BMHD,
ID_ACBM, ID_CAMG,
ID_ACBM, ID_CMAP,
ID_ACBM, ID_ABIT,
ID_ACBM, ID_ANNO,
ID_ACBM, ID_AUTH,
ID_ACBM, ID_Copyright,
ID_ACBM, ID_FVER,
ID_ACBM, ID_NAME
};
if( !(error = PropChunks( iff, (LONG *)propchunks, NUM_PROPCHUNKS )) )
{
/* Scan IFF stream until an error or an EOF occurs */
for( ;; )
{
if( error = ParseIFF( iff, IFFPARSE_STEP ) )
{
/* EOF (End Of File) is no error here... */
if( error == IFFERR_EOF )
{
error = 0L;
break;
}
/* bmhd header loaded ? */
if( bmhdprop == NULL )
{
if( bmhdprop = FindProp( iff, ID_ACBM, ID_BMHD ) )
{
*bmh = *((struct BitMapHeader *)(bmhdprop -> sp_Data));
/* ABIT data __must__ not be compressed for IFF ACBM */
if( (bmh -> bmh_Compression) != cmpNone )
{
error = DTERROR_INVALID_DATA;
}
}
}
/* camg loaded ? */
if( camgprop == NULL )
{
if( camgprop = FindProp( iff, ID_ACBM, ID_CAMG ) )
{
modeid = *(ULONG *)(camgprop -> sp_Data);
}
}
/* cmap loaded ? */
if( cmapprop == NULL )
{
if( cmapprop = FindProp( iff, ID_ACBM, ID_CMAP ) )
{
if( !CMAP2Object( cb, o, (cmapprop -> sp_Data), (cmapprop -> sp_Size) ) )
{
error = ERROR_NO_FREE_STORE;
}
}
}
/* annotation loaded ? */
if( annoprop == NULL )
{
/* IFF ANNO found ? */
if( annoprop = FindProp( iff, ID_ILBM, ID_ANNO ) )
{
STRPTR buff;
/* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
if( buff = (STRPTR)AllocVec( ((annoprop -> sp_Size) + 2UL), MEMF_ANY ) )
{
stccpy( buff, (annoprop -> sp_Data), (int)(annoprop -> sp_Size) );
SetDTAttrs( o, NULL, NULL, DTA_ObjAnnotation, buff, TAG_DONE );
FreeVec( buff );
}
else
{
/* no temp. buffer */
error = ERROR_NO_FREE_STORE;
}
}
}
/* autor loaded ? */
if( authprop == NULL )
{
/* IFF AUTH found ? */
if( authprop = FindProp( iff, ID_ILBM, ID_AUTH ) )
{
STRPTR buff;
/* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
if( buff = (STRPTR)AllocVec( ((authprop -> sp_Size) + 2UL), MEMF_ANY ) )
{
stccpy( buff, (authprop -> sp_Data), (int)(authprop -> sp_Size) );
SetDTAttrs( o, NULL, NULL, DTA_ObjAuthor, buff, TAG_DONE );
FreeVec( buff );
}
else
{
/* no temp. buffer */
error = ERROR_NO_FREE_STORE;
}
}
}
/* copyright loaded ? */
if( copyrightprop == NULL )
{
/* IFF (C) found ? */
if( copyrightprop = FindProp( iff, ID_ILBM, ID_Copyright ) )
{
STRPTR buff;
/* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
if( buff = (STRPTR)AllocVec( ((copyrightprop -> sp_Size) + 2UL), MEMF_ANY ) )
{
stccpy( buff, (copyrightprop -> sp_Data), (int)(copyrightprop -> sp_Size) );
SetDTAttrs( o, NULL, NULL, DTA_ObjCopyright, buff, TAG_DONE );
FreeVec( buff );
}
else
{
/* no temp. buffer */
error = ERROR_NO_FREE_STORE;
}
}
}
/* file version loaded ? */
if( fverprop == NULL )
{
/* IFF FVER found ? */
if( fverprop = FindProp( iff, ID_ILBM, ID_FVER ) )
{
STRPTR buff;
/* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
if( buff = (STRPTR)AllocVec( ((fverprop -> sp_Size) + 2UL), MEMF_ANY ) )
{
stccpy( buff, (fverprop -> sp_Data), (int)(fverprop -> sp_Size) );
SetDTAttrs( o, NULL, NULL, DTA_ObjVersion, buff, TAG_DONE );
FreeVec( buff );
}
else
{
/* no temp. buffer */
error = ERROR_NO_FREE_STORE;
}
}
}
/* name loaded ? */
if( nameprop == NULL )
{
/* IFF NAME found ? */
if( nameprop = FindProp( iff, ID_ILBM, ID_NAME ) )
{
STRPTR buff;
/* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
if( buff = (STRPTR)AllocVec( ((nameprop -> sp_Size) + 2UL), MEMF_ANY ) )
{
stccpy( buff, (nameprop -> sp_Data), (int)(nameprop -> sp_Size) );
SetDTAttrs( o, NULL, NULL, DTA_ObjName, buff, TAG_DONE );
FreeVec( buff );
}
else
{
/* no temp. buffer */
error = ERROR_NO_FREE_STORE;
}
}
}
/* abit loaded ? */
if( abitprop == NULL )
{
if( abitprop = FindProp( iff, ID_ACBM, ID_ABIT ) )
{
if( bmhdprop )
{
if( bm = AllocBitMap( (ULONG)(bmh -> bmh_Width), (ULONG)(bmh -> bmh_Height), (ULONG)(bmh -> bmh_Depth), 0UL, NULL ) )
{
error = LoadABITBody( bm, bmh, (abitprop -> sp_Data), (abitprop -> sp_Size) );
}
else
{
/* Not bitmap (AllocBitMap failed) */
error = ERROR_NO_FREE_STORE;
}
}
else
{
/* No BMHD chunk before ABIT chunk */
error = DTERROR_INVALID_DATA;
}
}
}
/* on error: leave for-loop */
if( error )
{
if( error != IFFERR_EOC )
{
break;
}
}
}
}
}
/* bmh, cmap, abit and all other required information available ? */
if( ((bmhdprop == NULL) || (cmapprop == NULL) || (abitprop == NULL) || (bm == NULL)) && (error == 0L) )
{
error = DTERROR_INVALID_DATA;
}
/* Any error ? */
if( error == 0L )
{
/* No name chunk ? */
if( nameprop == NULL )
{
STRPTR name;
GetDTAttrs( o, DTA_Name, (&name), TAG_DONE );
SetDTAttrs( o, NULL, NULL, DTA_ObjName, name, TAG_DONE );
}
/* No mode id ? */
if( modeid == 0UL )
{
/* Get best modeid for this dimensions */
modeid = BestModeID( BIDTAG_NominalWidth, (bmh -> bmh_PageWidth),
BIDTAG_NominalHeight, (bmh -> bmh_PageHeight),
BIDTAG_DesiredWidth, (bmh -> bmh_Width),
BIDTAG_DesiredHeight, (bmh -> bmh_Height),
BIDTAG_Depth, (bmh -> bmh_Depth),
BIDTAG_DIPFMustNotHave, (DIPF_IS_DUALPF | DIPF_IS_PF2PRI),
TAG_DONE );
if( modeid == INVALID_ID ) modeid = 0UL;
}
/* Set misc attributes */
SetDTAttrs( o, NULL, NULL,
PDTA_ModeID, modeid,
PDTA_BitMap, bm,
DTA_NominalHoriz, (bmh -> bmh_Width),
DTA_NominalVert, (bmh -> bmh_Height),
TAG_DONE );
}
}
else
{
/* No iff handle ? - Be sure we got a DTST_RAM sourcetype */
if( sourcetype != DTST_RAM )
{
/* No handle ! */
error = ERROR_REQUIRED_ARG_MISSING;
}
}
}
}
else
{
/* can't get required attributes from superclass */
error = ERROR_OBJECT_WRONG_TYPE;
}
/* Error codes below 0 are related to the IFFParse.library functions */
if( error < 0L )
{
/* convert IFFParse error to DOS error */
error = ifferr2doserr[ (-error - 1) ];
}
return( error );
}
/* Put CMAP chunk into picture/animation object... */
static
BOOL CMAP2Object( struct ClassBase *cb, Object *o, UBYTE *rgb, ULONG rgbsize )
{
struct ColorRegister *acm;
ULONG *acregs;
ULONG nc;
/* file has this many colors (e.g. each color has one byte per R,B,G-gun) */
nc = rgbsize / 3UL;
SetDTAttrs( o, NULL, NULL, PDTA_NumColors, nc, TAG_DONE );
/* Get color context */
if( GetDTAttrs( o,
PDTA_ColorRegisters, (&acm),
PDTA_CRegs, (&acregs),
PDTA_NumColors, (&nc),
TAG_DONE ) == 3UL )
{
/* All valid ? */
if( acm && acregs && nc )
{
ULONG i;
for( i = 0UL ; i < nc ; i++, acm++ )
{
acm -> red = *rgb++;
acm -> green = *rgb++;
acm -> blue = *rgb++;
/* Replicate the color information.
* This surrounds an OS bug which uses the low-order bytes of the 32-bit colors
* instead of the high order ones
*/
acregs[ ((i * 3) + 0) ] = ((ULONG)(acm -> red)) * 0x01010101UL;
acregs[ ((i * 3) + 1) ] = ((ULONG)(acm -> green)) * 0x01010101UL;
acregs[ ((i * 3) + 2) ] = ((ULONG)(acm -> blue)) * 0x01010101UL;
}
return( TRUE );
}
}
return( FALSE );
}
/* LOad IFF ACBM ABIT chunk into given bitmap */
static
LONG LoadABITBody( struct BitMap *bitmap, struct BitMapHeader *bmhd, BYTE *buffer, ULONG buffersize )
{
UBYTE srcPlaneCnt = bmhd -> bmh_Depth; /* Haven't counted for mask plane yet */
WORD srcRowBytes = RowBytes( (bmhd -> bmh_Width) );
WORD destRowBytes = bitmap -> BytesPerRow; /* used as a modulo only */
LONG nRows = bmhd -> bmh_Height;
LONG iPlane,
iRow;
BYTE *buf;
BYTE *planes[ MaxSrcPlanes ]; /* array of ptrs to planes & mask */
if( nRows > (bitmap -> Rows) )
nRows = bitmap -> Rows;
/* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
for( iPlane = 0 ; iPlane < (bitmap -> Depth) ; iPlane++ )
{
planes[ iPlane ] = (BYTE *)(bitmap -> Planes[ iPlane ]);
}
for( ; iPlane < MaxSrcPlanes ; iPlane++ )
{
planes[ iPlane ] = NULL;
}
/* Copy any mask plane ptr into corresponding "planes" slot. */
if( (bmhd -> bmh_Masking) == mskHasMask )
{
planes[ srcPlaneCnt ] = NULL; /* In case more dstPlanes than src. */
srcPlaneCnt += 1; /* Include mask plane in count. */
}
/* Read the ABIT contents into client's bitmap. */
buf = buffer;
for( iPlane = 0 ; iPlane < srcPlaneCnt ; iPlane++ )
{
for( iRow = nRows ; iRow > 0 ; iRow-- )
{
memcpy( planes[ iPlane ], buf, (size_t)srcRowBytes );
buf += srcRowBytes;
planes[ iPlane ] += destRowBytes; /* Possibly skipping unused bytes */
}
}
return( 0L );
}
/* The IFF ACBM encoder */
static
ULONG SaveIFFACBM( struct ClassBase *cb, Object *o, struct dtWrite *dtw )
{
ULONG retval = 0UL;
LONG error = 0L;
/* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
if( dtw -> dtw_FileHandle )
{
STRPTR objname,
objauthor,
objannotation,
objcopyright,
objversion;
struct BitMapHeader *bmh;
ULONG modeid;
ULONG *cregs;
ULONG numcolors;
struct BitMap *bm;
if( GetDTAttrs( o, DTA_ObjName, (&objname),
DTA_ObjAuthor, (&objauthor),
DTA_ObjAnnotation, (&objannotation),
DTA_ObjCopyright, (&objcopyright),
DTA_ObjVersion, (&objversion),
PDTA_BitMapHeader, (&bmh),
PDTA_ModeID, (&modeid),
PDTA_CRegs, (&cregs),
PDTA_NumColors, (&numcolors),
PDTA_BitMap, (&bm),
TAG_DONE ) == 10UL )
{
if( bmh && cregs && numcolors && bm )
{
/* ABIT data __must__ not be compressed for IFF ACBM */
if( (bmh -> bmh_Compression) == cmpNone )
{
/* Check if this is a standard amiga bitmap (we're accessing it directly below, and cannot
* handle any other bitmap layout than the standart planar format)
*/
if( GetBitMapAttr( bm, BMA_FLAGS ) & BMF_STANDARD )
{
struct IFFHandle *iff;
/* Create IFF handle based in the given file handle */
if( iff = CreateDOSIFFHandle( cb, (dtw -> dtw_FileHandle) ) )
{
if( !(error = OpenIFF( iff, IFFF_WRITE )) )
{
for( ;; ) /* not a loop, used as a jump table */
{
if( error = PushChunk( iff, ID_ACBM, ID_FORM, IFFSIZE_UNKNOWN ) )
break;
/* write BMHD (BitMapHeader) */
{
if( error = PushChunk( iff, 0UL, ID_BMHD, IFFSIZE_UNKNOWN ) )
break;
if( WriteChunkBytes( iff, (APTR)bmh, sizeof( struct BitMapHeader ) ) != sizeof( struct BitMapHeader ) )
{
error = IFFERR_WRITE;
break;
}
if( error = PopChunk( iff ) )
break;
}
/* write CMAP (global color map) */
if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
break;
/* write misc info (name, author, annotation etc.) */
if( error = PutIFFObjectInfo( cb, iff, objname, objauthor, objannotation, objcopyright, objversion ) )
break;
/* write CAMG (amiga view mode) (if available) */
if( (modeid != 0UL) && (modeid != INVALID_ID) )
{
if( error = PushChunk( iff, 0UL, ID_CAMG, IFFSIZE_UNKNOWN ) )
break;
if( WriteChunkBytes( iff, (APTR)(&modeid), sizeof( ULONG ) ) != sizeof( ULONG ) )
{
error = IFFERR_WRITE;
break;
}
if( error = PopChunk( iff ) )
break;
}
/* Write ACBM ABIT */
if( error = PutACBMABIT( cb, iff, bm, bmh ) )
break;
if( error = PopChunk( iff ) )
break;
break; /* end of jump table */
}
CloseIFF( iff );
}
/* No error == success */
if( error == 0L )
{
retval = 1UL; /* success ! */
}
FreeIFF( iff );
}
else
{
/* Can't alloc iff handle */
error = ERROR_NO_FREE_STORE;
}
}
else
{
/* unknown bitmap layout (e.g. not a standard amiga bitmap) */
error = ERROR_OBJECT_WRONG_TYPE;
}
}
else
{
/* IFF ACBM does not support compression */
error = DTERROR_UNKNOWN_COMPRESSION;
}
}
else
{
/* Some things are missing (e.g. no bitmap etc.)... */
error = DTERROR_NOT_ENOUGH_DATA;
}
}
else
{
/* Object does not support the attributes we need... */
error = ERROR_OBJECT_WRONG_TYPE;
}
}
/* Error codes below 0 are related to the IFFParse.library functions */
if( error < 0L )
{
/* convert IFFParse error to DOS error */
error = ifferr2doserr[ (-error - 1) ];
}
SetIoErr( error );
return( retval );
}
/* Create IFF handle based on given file handle */
static
struct IFFHandle *CreateDOSIFFHandle( struct ClassBase *cb, BPTR fh )
{
struct IFFHandle *iff;
if( iff = AllocIFF() )
{
iff -> iff_Stream = (ULONG)fh;
InitIFFasDOS( iff );
}
return( iff );
}
/* Put IFF generic info chunks (NAME, AUTH, ANNO, (C), FVER etc. */
static
LONG PutIFFObjectInfo( struct ClassBase *cb, struct IFFHandle *iff, STRPTR objname, STRPTR objauthor, STRPTR objannotation, STRPTR objcopyright, STRPTR objversion )
{
LONG error;
if( error = PutIFFString( cb, iff, ID_NAME, objname ) ) return( error );
if( error = PutIFFString( cb, iff, ID_AUTH, objauthor ) ) return( error );
if( error = PutIFFString( cb, iff, ID_ANNO, objannotation ) ) return( error );
if( error = PutIFFString( cb, iff, ID_Copyright, objcopyright ) ) return( error );
if( error = PutIFFString( cb, iff, ID_FVER, objversion ) ) return( error );
return( 0L );
}
/* write an string into a chunk (like generic AUTH, ANNO etc. chunks) */
static
LONG PutIFFString( struct ClassBase *cb, struct IFFHandle *iff, ULONG id, STRPTR string )
{
LONG error = 0L;
if( string )
{
ULONG len = (ULONG)(strlen( string ) + 1UL);
if( error = PushChunk( iff, 0UL, id, IFFSIZE_UNKNOWN ) )
return( error );
if( WriteChunkBytes( iff, (APTR)string, len ) != len )
{
return( IFFERR_WRITE );
}
error = PopChunk( iff );
}
return( error );
}
/* write ILBM CMAP */
static
LONG PutILBMCMAP( struct ClassBase *cb, struct IFFHandle *iff, ULONG *cregs, ULONG numcolors )
{
long error;
ULONG i;
struct ColorRegister cm;
if( error = PushChunk( iff, 0UL, ID_CMAP, IFFSIZE_UNKNOWN ) )
return( error );
for( i = 0UL ; i < numcolors ; i++ )
{
/* reduce colors from 32 bits to cmap's 8 bit-per-gun */
cm . red = (UBYTE)(cregs[ ((i * 3) + 0) ] >> 24UL);
cm . green = (UBYTE)(cregs[ ((i * 3) + 1) ] >> 24UL);
cm . blue = (UBYTE)(cregs[ ((i * 3) + 2) ] >> 24UL);
/* Write R, B, G bytes */
if( WriteChunkBytes( iff, (APTR)(&cm), 3UL ) != 3UL )
{
return( IFFERR_WRITE );
}
}
return( PopChunk( iff ) );
}
/*****************************************************************************/
/* Write ACBM ABIT data */
static
LONG PutACBMABIT( struct ClassBase *cb, struct IFFHandle *iff, struct BitMap *bitmap, struct BitMapHeader *bmh )
{
LONG error;
LONG rowBytes = bitmap -> BytesPerRow; /* for source modulo only */
LONG FileRowBytes = RowBytes( (bmh -> bmh_Width) ); /* width to write in bytes */
ULONG planeCnt = bmh -> bmh_Depth; /* number of bit planes including mask */
ULONG iPlane,
iRow;
BYTE *planes[ 24 ]; /* array of ptrs to planes & mask */
/* Copy the ptrs to bit & mask planes into local array "planes" */
for( iPlane = 0 ; iPlane < planeCnt; iPlane++ )
planes[ iPlane ] = (BYTE *)(bitmap -> Planes[ iPlane ]);
/* Write out a ABIT chunk header */
if( error = PushChunk( iff, 0L, ID_ABIT, IFFSIZE_UNKNOWN ) )
return( error );
/* Write out the ABIT contents */
for( iPlane = 0 ; iPlane < planeCnt ; iPlane++ )
{
for( iRow = bmh -> bmh_Height ; iRow > 0 ; iRow-- )
{
/* Write next row.*/
if( WriteChunkBytes( iff, planes[ iPlane ], FileRowBytes ) != FileRowBytes )
return( IFFERR_WRITE );
planes[ iPlane ] += rowBytes; /* Possibly skipping unused bytes */
}
}
/* Finish the chunk */
error = PopChunk( iff );
return( error );
}